package com.aplana.ccsd.service;

import info.magnolia.cms.core.MgnlNodeType;
import info.magnolia.jcr.util.ContentMap;
import info.magnolia.jcr.util.NodeUtil;
import info.magnolia.jcr.util.PropertyUtil;
import info.magnolia.jcr.wrapper.HTMLEscapingNodeWrapper;
import info.magnolia.module.blossom.dialog.DialogCreationContext;
import info.magnolia.module.blossom.dialog.TabBuilder;
import info.magnolia.module.categorization.controls.CategorizationUUIDMultiSelect;
import info.magnolia.module.data.DataModule;
import info.magnolia.module.templatingkit.dam.Asset;
import info.magnolia.module.templatingkit.dam.DAMSupport;
import info.magnolia.module.templatingkit.functions.STKTemplatingFunctions;
import info.magnolia.objectfactory.Classes;
import info.magnolia.objectfactory.Components;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.aplana.ccsd.constants.WebConstants;
import com.aplana.ccsd.model.Tag;

@Service
public class TemplatingServiceImpl implements TemplatingService {

	private static final Logger log = LoggerFactory
			.getLogger(TemplatingServiceImpl.class);

	@Override
	public String getNodePropertyAsHtml(Node node, String propName) {
		ContentMap contentMap = new ContentMap(NodeUtil.deepUnwrap(node,
				HTMLEscapingNodeWrapper.class));
		String text = (String) contentMap.get(propName);
		return text;
	}

	@Override
	public Asset getNodePropertyAsImage(Node node, String propName) {
		STKTemplatingFunctions stkFunctions = getStkFcn();
		Asset image = stkFunctions.getAsset(node, propName,
				DAMSupport.VARIATION_ORIGINAL);
		return image;
	}

	private STKTemplatingFunctions getStkFcn() {
		return Components.getComponent(STKTemplatingFunctions.class);
	}

	@Override
	public List<Node> getAreaComponents(Node areaNode)
			throws RepositoryException {
		Iterable<Node> nodeComponents = NodeUtil.getNodes(areaNode,
				MgnlNodeType.NT_COMPONENT);
		List<Node> components = new ArrayList<Node>();
		for (Node component : nodeComponents) {
			components.add(component);
		}
		return components;
	}

	@Override
	public void addTechnologyMultiSelectControl(TabBuilder tab, String name,
			String label, String description) throws RepositoryException {
		addDataMultiSelectControl(tab, name, label, description,
				WebConstants.TECHNOLOGY_NODE_TYPE,
				"com.aplana.ccsd.admininterface.TechnologySaveHandler");
	}

	@Override
	public void addIndustryMultiSelectControl(TabBuilder tab, String name,
			String label, String description) throws RepositoryException {
		addDataMultiSelectControl(tab, name, label, description,
				WebConstants.INDUSTRY_NODE_TYPE,
				"com.aplana.ccsd.admininterface.IndustrySaveHandler");
	}

	private void addDataMultiSelectControl(TabBuilder tab, String name,
			String label, String description, String tree,
			String saveHandlerClass) throws RepositoryException {
		CategorizationUUIDMultiSelect control = Classes.getClassFactory()
				.newInstance(CategorizationUUIDMultiSelect.class);
		control.setName(name);
		control.setLabel(label);
		control.setDescription(description);

		DialogCreationContext context = tab.getContext();
		control.init(context.getRequest(), context.getResponse(),
				context.getWebsiteNode(), null);

		control.setConfig("tree", tree);
		control.setConfig("saveHandler", saveHandlerClass);
		control.setConfig("type", PropertyType.STRING);
		control.setConfig("repository", DataModule.getRepository());
		control.setConfig("i18nBasename",
				"info.magnolia.module.categorization.messages");
		tab.getTab().addSub(control);
	}

	@Override
	public List<Node> getNodePropertyAsDataTypes(Node node, String propName)
			throws ValueFormatException, IllegalStateException,
			RepositoryException {
		List<Node> res = new ArrayList<Node>();

		if (node.hasProperty(propName)) {
			Property property = PropertyUtil.getProperty(node, propName);
			Value[] categories = property.getValues();
			for (Value value : categories) {
				Node categoryNode = NodeUtil.getNodeByIdentifier(
						DataModule.getRepository(), value.getString());
				if (categoryNode != null) {
					res.add(categoryNode);
				}
			}
			this.getSortedList(node, res);
		}

		return res;
	}

	private List<Node> getSortedList(Node node, List<Node> temp)
			throws ValueFormatException, RepositoryException {

		String order = PropertyUtil.getString(node, "order");
		if (!StringUtils.isEmpty(order)) {
			// first criteria always by name then whatever
			Collections.sort(temp, orderBy("name"));
			Collections.reverse(temp);
			if (!order.equals("name")) {
				Collections.sort(temp, orderBy(order));
			}

		}
		return temp;
	}

	private Comparator<Node> orderBy(final String value) {
		return new Comparator<Node>() {
			@Override
			public int compare(Node m0, Node m1) {
				try {
					return PropertyUtil
							.getProperty(m1, value)
							.getString()
							.compareToIgnoreCase(
									PropertyUtil.getProperty(m0, value)
											.getString());
				} catch (ValueFormatException e) {
					log.debug("No order property define", e);
					return 0;
				} catch (RepositoryException e) {
					log.debug("No order property define", e);
					return 0;
				}
			}
		};

	}

	@Override
	public List<Tag> getNodePropertyAsTags(Node node, String propName)
			throws ValueFormatException, IllegalStateException,
			RepositoryException {
		List<Node> types = getNodePropertyAsDataTypes(node, propName);
		List<Tag> tags = new ArrayList<Tag>();
		for (Node type : types) {
			tags.add(new Tag(PropertyUtil.getString(type, "name"), PropertyUtil
					.getString(type, "displayName")));
		}

		return tags;
	}

}